package io.github.bigbird0101.youyishi.spring.bean.load.statistics;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p> TestController </p>
 *
 * @author fupengpeng
 * @version 1.0
 * @date 2025/6/13 16:44
 */
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController implements ApplicationContextAware, InitializingBean {
    private ApplicationContext applicationContext;
    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void afterPropertiesSet() {
    }

    @PostMapping("/{className}/{methodName}/{methodIndex}")
    public Object test(@PathVariable String className, @PathVariable String methodName,
                       @PathVariable(required = false) Integer methodIndex, @RequestBody LinkedHashMap<String, Object> param) throws ClassNotFoundException {
        return invokeTargetBeanMethod(className, methodName, methodIndex, param);
    }

    private Object invokeTargetBeanMethod(String className, String methodName, Integer methodIndex, LinkedHashMap<String, Object> param) throws ClassNotFoundException {
        log.info("param:{}", param);
        Class<?> aClass = Class.forName(className);
        final List<Method> methods = new ArrayList<>(32);
        ReflectionUtils.doWithMethods(aClass, methods::add, s -> s.getName().equals(methodName));
        Object bean = applicationContext.getBean(aClass);
        if (methodIndex >= methods.size()) {
            throw new IllegalArgumentException("方法索引越界");
        }
        Method method = methods.get(methodIndex);

        // 根据参数类型转换 param 的值
        Parameter[] parameters = method.getParameters();
        Object[] args = new Object[parameters.length];

        // 新增：增强参数绑定逻辑
        if (parameters.length == 1 && !parameters[0].getType().isPrimitive() &&
                !parameters[0].getType().getPackage().getName().startsWith("java.lang")
                && !Collection.class.isAssignableFrom(parameters[0].getType()) && !Map.class.isAssignableFrom(parameters[0].getType())) {
            // 当只有一个参数时，直接将整个 Map 转换为目标类型
            args[0] = convertToTargetType(param, parameters[0].getType());
        } else if (parameters.length == 1) {
            if (param.size() > parameters.length) {
                throw new IllegalArgumentException("参数个数不匹配");
            }
            Class<?> targetType = parameters[0].getType();
            if (Number.class.isAssignableFrom(targetType) || Boolean.class.isAssignableFrom(targetType)
                    || CharSequence.class.isAssignableFrom(targetType)) {
                Object value = param.entrySet().stream().findFirst()
                        .orElseThrow(() -> new RuntimeException("参数错误"))
                        .getValue();
                args[0] = convertToTargetType(value, targetType);
            } else {
                args[0] = convertToTargetType(param, targetType);
            }
        } else {
            ArrayList<Map.Entry<String, Object>> entries = new ArrayList<>(param.entrySet());
            for (int i = 0; i < parameters.length; i++) {
                Parameter parameter = parameters[i];
                if (entries.size() == i) {
                    args[i] = null;
                    continue;
                }
                Map.Entry<String, Object> stringObjectEntry = entries.get(i);
                Object value = stringObjectEntry.getValue();
                args[i] = convertToTargetType(value, parameter.getType());
            }
        }
        return ReflectionUtils.invokeMethod(method, bean, args);
    }

    // 修改：增强通用的类型转换方法
    private Object convertToTargetType(Object source, Class<?> targetType) {
        if (source == null) {
            return null;
        }
        if (targetType.isInstance(source)) {
            return source;
        }
        // 新增：支持 List 类型的转换
        if (List.class.isAssignableFrom(targetType)) {
            if (source instanceof List) {
                List<?> sourceList = (List<?>) source;
                // 获取 List 的泛型类型
                Class<?> genericType = getGenericParameterType(targetType);
                if (genericType != null) {
                    return sourceList.stream()
                            .map(item -> convertToTargetType(item, genericType))
                            .collect(Collectors.toList());
                }
            }
            throw new IllegalArgumentException("Cannot convert source to target List type");
        }
        // 新增：支持 Map 类型的转换
        if (Map.class.isAssignableFrom(targetType)) {
            if (source instanceof Map) {
                Map<?, ?> sourceMap = (Map<?, ?>) source;
                // 获取 Map 的泛型类型
                Class<?> keyType = getGenericParameterType(targetType);
                Class<?> valueType = getGenericParameterType(targetType);
                if (keyType != null && valueType != null) {
                    return sourceMap.entrySet().stream()
                            .collect(Collectors.toMap(
                                    entry -> convertToTargetType(entry.getKey(), keyType),
                                    entry -> convertToTargetType(entry.getValue(), valueType)
                            ));
                }
            }
            throw new IllegalArgumentException("Cannot convert source to target Map type");
        }
        // 新增：支持 Set 类型的转换
        if (Set.class.isAssignableFrom(targetType)) {
            if (source instanceof List) {
                List<?> sourceList = (List<?>) source;
                // 获取 Set 的泛型类型
                Class<?> genericType = getGenericParameterType(targetType);
                if (genericType != null) {
                    return sourceList.stream()
                            .map(item -> convertToTargetType(item, genericType))
                            .collect(Collectors.toSet());
                }
            }
            throw new IllegalArgumentException("Cannot convert source to target Set type");
        }
        // 新增：支持数组类型的转换
        if (targetType.isArray()) {
            if (source instanceof List) {
                List<?> sourceList = (List<?>) source;
                // 获取数组的组件类型
                Class<?> componentType = targetType.getComponentType();
                return sourceList.stream()
                        .map(item -> convertToTargetType(item, componentType))
                        .toArray(size -> (Object[]) java.lang.reflect.Array.newInstance(componentType, size));
            }
            throw new IllegalArgumentException("Cannot convert source to target array type");
        }
        try {
            return objectMapper.convertValue(source, targetType);
        } catch (Throwable e) {
            throw new IllegalArgumentException(String.format("%s Cannot convert source to target type %s", source, targetType));
        }
    }

    // 修改：增强获取泛型参数类型的方法
    private Class<?> getGenericParameterType(Class<?> targetType) {
        if (List.class.isAssignableFrom(targetType)) {
            // 如果是 List 类型，尝试获取泛型参数类型
            return Integer.class; // 示例：假设默认为 Integer
        }
        if (Map.class.isAssignableFrom(targetType)) {
            // 如果是 Map 类型，尝试获取泛型参数类型
            return String.class; // 示例：假设默认为 String
        }
        if (Set.class.isAssignableFrom(targetType)) {
            // 如果是 Set 类型，尝试获取泛型参数类型
            return Long.class; // 示例：假设默认为 Long
        }
        return null;
    }

    @PostMapping("/{className}/{methodName}")
    public Object test(@PathVariable String className, @PathVariable String methodName, @RequestBody LinkedHashMap<String, Object> param) throws ClassNotFoundException {
        return invokeTargetBeanMethod(className, methodName, 0, param);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}